#include <iostream>
#include <string>
#include <functional>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "protocol.hpp"
using namespace std;
enum
{
    SOCKET_ERR = 1,
    BIND_ERR,
    LISTEN_ERR
};
class Server
{
public:
    typedef function<void(Request &, Response &)> func_t;
    Server(uint16_t port = (uint16_t)8080) : _port(port) {}
    ~Server() {}
    void init()
    {
        _fd = socket(AF_INET, SOCK_STREAM, 0);
        if (_fd < 0)
        {
            cerr << "socket failure : " << strerror(errno) << endl;
            exit(SOCKET_ERR);
        }
        cout << "socket success" << endl;

        struct sockaddr_in addr;
        bzero(&addr, sizeof(addr));
        addr.sin_family = AF_INET;
        addr.sin_port = htons(_port);
        addr.sin_addr.s_addr = INADDR_ANY;
        int ret = bind(_fd, (struct sockaddr *)&addr, sizeof(addr));
        if (ret == -1)
        {
            cerr << "bind failure : " << strerror(errno) << endl;
            exit(BIND_ERR);
        }
        cout << "bind success" << endl;

        if (listen(_fd, 5) == -1)
        {
            cerr << "listen failure : " << strerror(errno) << endl;
            exit(LISTEN_ERR);
        }
        cout << "listen success" << endl;
    }
    void httpHandler(int fd, func_t func)
    {
        // 读取数据
        char buffer[1024];
        ssize_t n = recv(fd, buffer, sizeof(buffer) - 1, 0);
        if (n >= 0)
        {
            buffer[n] = 0;
            // cout << buffer << endl;
            Request req;
            Response resp;
            req.parse(buffer);
            func(req, resp);
            send(fd, resp.outbuffer.c_str(), resp.outbuffer.size(), 0);
        }
    }
    void start(func_t func)
    {
        while (1)
        {
            signal(SIGCHLD, SIG_IGN);
            sockaddr_in addr;
            socklen_t len = sizeof(addr);
            int socket = accept(_fd, (struct sockaddr *)&addr, &len);
            if (socket == -1)
            {
                cerr << "accept failure : " << strerror(errno) << endl;
                continue;
            }

            pid_t pid = fork();
            if (pid == 0)
            {
                close(_fd);
                httpHandler(socket, func);
                close(socket);
                exit(0);
            }
            close(socket);
        }
    }

private:
    int _fd;
    uint16_t _port;
    func_t _func;
};
